package com.smsc.headend.task.engine.executor.impl.generalparam;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.smsc.headend.common.enums.errorcode.TaskExecuteErrorCode;
import com.smsc.headend.common.utils.RedisUtils;
import com.smsc.headend.module.asset.dmo.ComConfigDMO;
import com.smsc.headend.module.asset.dmo.MeterConfigDMO;
import com.smsc.headend.module.asset.entity.ComEntity;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.common.entity.DeviceOperation;
import com.smsc.headend.module.common.entity.ScalerUnit;
import com.smsc.headend.module.data.dmo.DeviceSAPandKeys;
import com.smsc.headend.module.data.dto.DLMSSubDataItemDTO;
import com.smsc.headend.module.data.dto.DataItemDTO;
import com.smsc.headend.module.data.enums.DictionaryType;
import com.smsc.headend.module.data.enums.OperationGroup;
import com.smsc.headend.module.protocol.cosem.enums.DlmsDataType;
import com.smsc.headend.module.protocol.cosem.util.ByteUtils;
import com.smsc.headend.module.scheme.entity.ConfigScheduleTask;
import com.smsc.headend.module.task.consts.TaskKafkaTopic;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.AtomicTaskState;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.module.task.enums.DeviceActionType;
import com.smsc.headend.module.task.enums.SubTaskStatus;
import com.smsc.headend.module.task.enums.TaskType;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskExecutorException;
import com.smsc.headend.task.engine.executor.TaskExecutor;
import com.smsc.headend.task.engine.facade.DataItemFacade;
import com.smsc.headend.task.engine.handler.impl.deviceconfig.SetStepTariffHandler;
import com.smsc.headend.task.engine.handler.impl.generalparam.SetGeneralParamHandler;
import com.smsc.headend.task.engine.service.ConnectorService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import com.smsc.headend.task.engine.service.task.TaskPacketService;
import com.smsc.headend.task.engine.utils.CustomCosemUtil;
import gurux.dlms.GXDate;
import gurux.dlms.GXDateTime;
import gurux.dlms.GXTime;
import gurux.dlms.enums.ClockStatus;
import gurux.dlms.enums.DateTimeSkips;
import gurux.dlms.enums.ObjectType;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author wxh
 * @date 2021/5/8 11:06
 */
public class SetGeneralParamExecutor implements TaskExecutor {
    public static final String VALUE = "value";
    @Autowired
    TaskPacketService packetService;
    @Autowired
    ConnectorService connectorService;
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    FeignAssetManagementService assetManagementRemoteService;
    @Autowired
    DataItemFacade dataItemFacade;
    @Autowired
    TaskDAO taskDAO;
    @Autowired
    AssetService assetService;
    @Autowired
    KafkaTemplate kafkaTemplate;

    @Override
    public AtomicTaskState execute(Task task, AtomicTask atomicTask) throws UDISTaskExecutorException {
        DeviceOperation dictionary = assetService.getDictionary(atomicTask.getOperationId(), DictionaryType.Operation.getType());

        Meter meter = getMeter(task, assetService);
        MeterConfigDMO meterConfigDMO = task.getMeterId() == null ? null : assetService.getMeterConfigById(task.getMeterId());
        ComEntity terminal = assetService.getComById(task.getComId());
        ComConfigDMO comConfigDMO = assetService.getComConfigById(task.getComId());
        List<DataItemDTO> dataItemCosemList = dataItemFacade.getDataItemsByOperation(meter, terminal, dictionary, getParameterMap(task, atomicTask), comConfigDMO.getModelId());
        if (CollectionUtils.isEmpty(dataItemCosemList)) {
            throw new UDISTaskExecutorException(TaskExecuteErrorCode.NO_DATA_ITEM.toString());
        }
        DeviceOperation operationGroup = assetService.getDictionary(atomicTask.getGroupId(), DictionaryType.OperationGroup.getType());
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemCosemList.get(0);
        if (dlmsSubDataItemDTO.getClassId() == 300) {
            // classId为300 自定义为 GPRS AT指令
            if (!StrUtil.equals("P2P", meter.getChannelType())) {
                throw new UDISTaskExecutorException(TaskExecuteErrorCode.NOT_P2P_METER.toString());
            }
            Map<String, Object> map = JSONUtil.toBean(atomicTask.getAtomicTaskParam(), Map.class);
            if (map.get("value") == null || !Convert.toStr(map.get("value")).startsWith("AT+")) {
                throw new UDISTaskExecutorException(TaskExecuteErrorCode.INVALID_AT_CMD.toString());
            }
            String atCmd = Convert.toStr(map.get("value")).trim();
            byte[][] packets = new byte[][]{atCmd.getBytes(StandardCharsets.UTF_8)};
            log.info(ByteUtils.byteToHexString(packets[0]));
            connectorService.sendAtCmdPacket(task, atomicTask, dataItemCosemList.get(0).getRoleId(), task.getIsODR(), true, packets);
        } else if(dlmsSubDataItemDTO.getClassId() == 301) {
            // classId为301 自定义为报文下发指令
            Map<String, Object> map = JSONUtil.toBean(atomicTask.getAtomicTaskParam(), Map.class);
            String packetVValue = Convert.toStr(map.get("value")).replaceAll("\\s+", "");
            Matcher matcher = Pattern.compile("[0-9A-Fa-f]+").matcher(packetVValue);
            if (!matcher.matches()){
                throw new UDISTaskExecutorException(TaskExecuteErrorCode.INVALID_PACKET.toString());
            }

            byte[] bytes = ByteUtils.hexStringToByte(packetVValue);
            byte[][] packets = new byte[][]{bytes};
            log.info(ByteUtils.byteToHexString(packets[0]));
            connectorService.sendAtCmdPacket(task, atomicTask, dataItemCosemList.get(0).getRoleId(), task.getIsODR(), true, packets);
        } else {
            DeviceSAPandKeys deviceKeys = assetManagementRemoteService.getMeterCommunicationKey(meter.getMeterId(), dataItemCosemList.get(0).getRoleId());
            byte[][] packets = getPacketByOperationGroup(task, atomicTask, meterConfigDMO, deviceKeys, operationGroup, dataItemCosemList, meter);
            if (packets == null) {
                log.info("packet is null");
                throw new UDISTaskExecutorException(TaskExecuteErrorCode.BUILD_PACKET_ERROR.toString());
            }
            log.info(ByteUtils.byteToHexString(packets[0]));
            connectorService.sendPacket(task, atomicTask, dataItemCosemList.get(0).getRoleId(), task.getIsODR(), packets);
        }
        if (StrUtil.equalsIgnoreCase(task.getTaskType(),TaskType.SetRelayControlMode.name())) {
            assetManagementRemoteService.updateLogRelayControl(task.getTaskNo(), meter.getMeterId(), ConfigScheduleTask.ActionType.SET_DEVICE_CONFIG.getType(), SubTaskStatus.Processing.getCode(),null, null);
        }
        Class handlerClass = getHandlerClass(atomicTask);
        return createAtomicState(handlerClass);
    }

    private byte[][] getPacketByOperationGroup(Task task, AtomicTask atomicTask, MeterConfigDMO meterConfigDMO, DeviceSAPandKeys deviceKeys, DeviceOperation operationGroup, List<DataItemDTO> dataItemCosemList, Meter meter) throws UDISTaskExecutorException {
        byte[][] packet = null;
        OperationGroup operationGp = OperationGroup.forId(operationGroup.getOptId().intValue());
        switch (operationGp) {
            case GeneralParametersSet:
            case StepTariffActiveDateSet:
            case StPaymentControlConfigSet:
            case StFunctionControlConfigSet:
            case StepTariffBackUpRatePriceSet:
            case StepTariffBackUpStepSet:
                packet = writeGeneralParameter(task, atomicTask, meterConfigDMO, deviceKeys, meter, dataItemCosemList);
                break;
        }
        return packet;
    }

    private byte[][] writeGeneralParameter(Task task, AtomicTask atomicTask, MeterConfigDMO meterConfigDMO, DeviceSAPandKeys deviceKeys, Meter meter, List<DataItemDTO> dataItemCosemList) throws UDISTaskExecutorException {
        byte[][] packet = null;
        DataItemDTO subDataItemDto = dataItemCosemList.get(0);
        switch (ObjectType.forValue(((DLMSSubDataItemDTO) subDataItemDto).getClassId())) {
            case DATA:
            case REGISTER:
            case EXTENDED_REGISTER:
                packet = setSimpleDataTypePacket(task, dataItemCosemList, meter, atomicTask, meterConfigDMO);
                break;
            case ACTION_SCHEDULE:
                packet = setActionSchedule(dataItemCosemList, meter, atomicTask, meterConfigDMO, deviceKeys);
                break;
            case DISCONNECT_CONTROL:
                packet = setDisconnectControlPacket(dataItemCosemList, meter, atomicTask, meterConfigDMO);
                break;
        }
        return packet;
    }


    private byte[][] setActionSchedule(List<DataItemDTO> dataItemCosemList, Meter meter, AtomicTask atomicTask, MeterConfigDMO meterConfigDMO, DeviceSAPandKeys deviceKeys) throws UDISTaskExecutorException {
        byte[][] packet = null;
        DataItemDTO dataItemDto = dataItemCosemList.get(0);
        Map<String, Object> map = JSONUtil.toBean(atomicTask.getAtomicTaskParam(), Map.class);
        switch (((DLMSSubDataItemDTO) dataItemDto).getAttributeId()) {
            case 4: // execution_time
                String timeDateValue = Convert.toStr(map.get(VALUE));
                String[] list = timeDateValue.split(";");
                List<GXDate> gxDates = new ArrayList<>();
                List<GXTime> gxTimes = new ArrayList<>();
                for (String timeDate:list) {
                    String timeValue = timeDate.split(",")[0];
                    GXTime gxTime = getGxTime(timeValue, true);
                    String dateValue = timeDate.split(",")[1];
                    GXDate gxDate = getGxDate(dateValue, true);

                    gxDates.add(gxDate);
                    gxTimes.add(gxTime);
                }
                packet = new byte[][]{packetService.setScheduleAction(dataItemCosemList.get(0), meter,  meterConfigDMO, deviceKeys, gxDates, gxTimes)};
                break;
            default:
                throw new UDISTaskExecutorException(TaskExecuteErrorCode.NO_IMPLEMENTATION_CURRENTLY.toString());
        }
        return packet;
    }


    private byte[][] setDisconnectControlPacket(List<DataItemDTO> dataItemCosemList, Meter meter, AtomicTask atomicTask, MeterConfigDMO meterConfigDMO) throws UDISTaskExecutorException {
        byte[][] packet = null;
        DataItemDTO dataItemDto = dataItemCosemList.get(0);
        Map<String, Object> map = JSONUtil.toBean(atomicTask.getAtomicTaskParam(), Map.class);
        switch (((DLMSSubDataItemDTO) dataItemDto).getAttributeId()) {
            case 4: // control_mode (enum)
                packet = new byte[][]{packetService.writeSimpleDataPacket(dataItemCosemList, meter, Convert.toInt(map.get(VALUE)), meterConfigDMO)};
                break;
            default:
                throw new UDISTaskExecutorException(TaskExecuteErrorCode.NO_IMPLEMENTATION_CURRENTLY.toString());
        }
        return packet;
    }

    private byte[][] setSimpleDataTypePacket(Task task, List<DataItemDTO> dataItemCosemList, Meter meter, AtomicTask atomicTask, MeterConfigDMO meterConfigDMO) throws UDISTaskExecutorException {
        byte[][] packet = setSpecialDataPacket(task, dataItemCosemList, meter, atomicTask, meterConfigDMO);
        if (packet != null) {
            return packet;
        }
        DLMSSubDataItemDTO dlmsSubDataItemDTO = (DLMSSubDataItemDTO) dataItemCosemList.get(0);
        DlmsDataType dlmsDataType = DlmsDataType.forName(dlmsSubDataItemDTO.getObjType());
        if (dlmsDataType == null) {
            log.info("invalid data type configured in db {}", dlmsSubDataItemDTO.getObjType());
            throw new UDISTaskExecutorException(TaskExecuteErrorCode.INVALID_DATA_TYPE.toString());
        }
        Map<String, Object> map = JSONUtil.toBean(atomicTask.getAtomicTaskParam(), Map.class);
        byte[][] results = null;
        Object value;
        switch (dlmsDataType) {
            case Boolean:
                value = Convert.toBool(map.get(VALUE)) ? 1 : 0;
                break;
            case DoubleLong:
            case DoubleLongUnsigned:
            case Long:
            case Integer:
            case Unsigned:
            case LongUnsigned:
                value = getConvertValue(map, meter, dataItemCosemList);
                break;
            case Enum:
                value = Convert.toInt(map.get(VALUE));
                break;
            case Float32:
                value = Convert.toFloat(map.get(VALUE));
                break;
            case Float64:
                value = Convert.toDouble(map.get(VALUE));
                break;
            case Time:
                // 格式为 hh:mm:ss
                value = getGxTime(Convert.toStr(map.get(VALUE)), false);
                break;
            case OctetString:
                value = Convert.toStr(map.get(VALUE));
                String valueStr = (String) value;
                if (Pattern.matches("[0-9]{2}:[0-9]{2}:[0-9]{2}", valueStr)) {
                    // 时间格式的需要特殊转换
                    value = getGxTime(Convert.toStr(value), false);
                }
                if (Pattern.matches("\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}", valueStr)) {
                    value = getGxDateTime(valueStr);
                }
                break;
            case Date:
                value = Convert.toStr(map.get(VALUE));
                // 年份格式为 YYYY-MM-DD
                value = getGxDate(Convert.toStr(value), false);
                break;
            case BitString:
                // 00001111格式
                value = Convert.toStr(map.get(VALUE));
                break;
            case Array:
                results = getArrayPacketForGeneralSet(dataItemCosemList, meter, meterConfigDMO, Convert.toStr(map.get(VALUE)));
            default:
                value = Convert.toStr(map.get(VALUE));
                break;
        }

        if (value != null && results == null) {
            results = new byte[][]{packetService.writeSimpleDataPacket(dataItemCosemList, meter, value, meterConfigDMO)};
        }
        return results;
    }

    private GXDateTime getGxDateTime(String valueStr) {
        Date time = DateUtil.parse(valueStr);
        GXDateTime gxDateTime = new GXDateTime(time);
        gxDateTime.getSkip().add(DateTimeSkips.DEVITATION);
        gxDateTime.getStatus().add(ClockStatus.SKIPPED);
        return gxDateTime;
    }

    private byte[][] getArrayPacketForGeneralSet(List<DataItemDTO> dataItemCosemList, Meter meter, MeterConfigDMO meterConfigDMO, String arraySetting) throws UDISTaskExecutorException {
        List<String> collect = Arrays.stream(arraySetting.split(",")).collect(Collectors.toList());
        //暂时只给埃及POC增加 DoubleLongUnsignedArray的下发
        List<Long> convertValueArray = getConvertValueArray(meter, collect, dataItemCosemList);
        return packetService.setLongArrayToData(dataItemCosemList.get(0), meterConfigDMO, convertValueArray);
    }

    private byte[][] setSpecialDataPacket(Task task, List<DataItemDTO> dataItemCosemList, Meter meter, AtomicTask atomicTask, MeterConfigDMO meterConfigDMO) throws UDISTaskExecutorException {
        DataItemDTO dataItemDTO = dataItemCosemList.get(0);
        Map<String, Object> map = JSONUtil.toBean(atomicTask.getAtomicTaskParam(), Map.class);
        byte[][] packet = null;
        switch (Convert.toStr(dataItemDTO.getSubDataItemId())) {
            case "1020010111102": // Friendly Time
                Object value = null;
                if (StrUtil.equals(TaskType.WsMdmSetParameter.toString(), task.getTaskType())) {
                    // vending接口 Friendly Time 格式 16001100 需要转成 10000B00
                    value = CustomCosemUtil.formatVendingFriendTimeStrToHex(Convert.toStr(map.get("value")));
                } else {
                    // web Friendly Time 格式 [16:00, 11:00] 需要转成 10000B00
                    value = CustomCosemUtil.formatFriendTimeStrToHex(Convert.toStr(map.get("value")));
                }
                packet = new byte[][]{packetService.writeSimpleDataPacket(dataItemCosemList, meter, value, meterConfigDMO)};
                break;
            case "1020010112102": // Friendly Weekday
                if (StrUtil.equals(TaskType.WsMdmSetParameter.toString(), task.getTaskType())) {
                    // vending接口 Friendly Weekday 0011110 (约定的格式 每位代表周一到周日) 需要转换成bit-string 01111000 (反转补个0)
                    value = "0" + StrUtil.reverse(Convert.toStr(map.get("value")));
                    packet = new byte[][]{packetService.writeSimpleDataPacket(dataItemCosemList, meter, value, meterConfigDMO)};
                }
                break;
            case "1020010106102": // Active date of  passive tariff table
                if (StrUtil.equals(TaskType.WsMdmSetParameter.toString(), task.getTaskType())) {
                    // vending接口 Active date of  passive tariff table格式为20200101 (YYYYMMDD)
                    String dateStr = Convert.toStr(map.get("value"));
                    int year = Convert.toInt(dateStr.substring(0, 4));
                    int month = Convert.toInt(dateStr.substring(4, 6));
                    int day = Convert.toInt(dateStr.substring(6, 8));
                    GXDateTime gxDateTime = new GXDateTime(year, month, day, 0, 0, 0, 1); // millseconds设置1-9的时候 报文为00
                    packet = new byte[][]{packetService.writeSimpleDataPacket(dataItemCosemList, meter, gxDateTime, meterConfigDMO)};
                } else {
                    // web 通用参数发过来的任务 日期格式为 YYYY-MM-DD HH:MM:SS 格式暂不做校验 可能为FFFF-FF-FF FF:FE:12格式 参数类型为octect_string不是
                    String dateStr = Convert.toStr(map.get(VALUE));
                    int year = NumberUtils.isDigits(dateStr.substring(0, 4)) ? Integer.parseInt(dateStr.substring(0, 4), 10) : Integer.parseInt(dateStr.substring(0, 4), 16);
                    int month = NumberUtils.isDigits(dateStr.substring(5, 7)) ? Integer.parseInt(dateStr.substring(5, 7), 10) : Integer.parseInt(dateStr.substring(5, 7), 16);
                    int day = NumberUtils.isDigits(dateStr.substring(8, 10)) ? Integer.parseInt(dateStr.substring(8, 10), 10) : Integer.parseInt(dateStr.substring(8, 10), 16);
                    int hour = NumberUtils.isDigits(dateStr.substring(11, 13)) ? Integer.parseInt(dateStr.substring(11, 13), 10) : Integer.parseInt(dateStr.substring(11, 13), 16);
                    int minute = NumberUtils.isDigits(dateStr.substring(14, 16)) ? Integer.parseInt(dateStr.substring(14, 16), 10) : Integer.parseInt(dateStr.substring(14, 16), 16);
                    int second = NumberUtils.isDigits(dateStr.substring(17, 19)) ? Integer.parseInt(dateStr.substring(17, 19), 10) : Integer.parseInt(dateStr.substring(17, 19), 16);
                    GXDateTime gxDateTime = new GXDateTime(year, month, day, hour, minute, second, 1); // millseconds设置1-9的时候 报文为00
                    return new byte[][]{packetService.writeSimpleDataPacket(dataItemCosemList, meter, gxDateTime, meterConfigDMO)};
                }

                break;
        }
        return packet;
    }

    @Override
    public Boolean handleFailure(Task task, AtomicTask atomicTask, String message) {
        log.info("error {}, ", message);
        Map<String, Object> param = getParameterMap(task, atomicTask);
        Long subDataItemId = Long.valueOf(String.valueOf(param.get("subDataItemId")));
        if (task.getIsODR()) {
            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(subDataItemId), message, 600L, false);
        }
        // Vending接口下发结果处理
        if (StrUtil.equals(TaskType.WsMdmSetParameter.toString(), task.getTaskType())) {
            handleSetParameterResult(task, atomicTask, message);
        }
        if (StrUtil.equalsIgnoreCase(task.getTaskType(),TaskType.SetRelayControlMode.name())) {
            assetManagementRemoteService.updateLogRelayControl(task.getTaskNo(), task.getMeterId(), ConfigScheduleTask.ActionType.SET_DEVICE_CONFIG.getType(), SubTaskStatus.Failed.getCode(),null, message);
        }
        return true;
    }

    private Long getConvertValue(Map<String, Object> map, Meter meter, List<DataItemDTO> dataItemCosemList) throws UDISTaskExecutorException {
        Object value = map.get(VALUE);
        String valueStr = Convert.toStr(value);
        ScalerUnit scalerUnit = assetManagementRemoteService.getScalerUnitByModelIdSubDataItemId(meter.getModelId(), dataItemCosemList.get(0).getSubDataItemId());
        return getConvertLong(valueStr, scalerUnit);
    }

    private List<Long> getConvertValueArray(Meter meter, List<String> collect, List<DataItemDTO> dataItemCosemList) throws UDISTaskExecutorException {
        ScalerUnit scalerUnit = assetManagementRemoteService.getScalerUnitByModelIdSubDataItemId(meter.getModelId(), dataItemCosemList.get(0).getSubDataItemId());
        AtomicReference<Boolean> isConvertFailed = new AtomicReference<>(false);
        List<Long> result = collect.stream().map(v -> {
            try {
                return getConvertLong(v, scalerUnit);
            } catch (UDISTaskExecutorException e) {
                isConvertFailed.set(true);
            }
            return null;
        }).collect(Collectors.toList());

        if (isConvertFailed.get()) {
            throw new UDISTaskExecutorException(TaskExecuteErrorCode.DATA_CONVERT_ERROR.toString());
        }
        return result;
    }

    private Long getConvertLong(String valueStr, ScalerUnit scalerUnit) throws UDISTaskExecutorException {
        if (scalerUnit != null) {
            BigDecimal val = new BigDecimal(valueStr).divide(BigDecimal.valueOf(Math.pow(10, scalerUnit.getScaler())));
            if (new BigDecimal(val.longValue()).compareTo(val) != 0) {
                // 转换后不能是小数下发
                log.info("invalid value after convert {} {}", valueStr, scalerUnit.getScaler());
                throw new UDISTaskExecutorException(TaskExecuteErrorCode.DATA_CONVERT_ERROR.toString());
            }
            return val.longValue();
        }
        // set不能是小数下发到电表
        if (NumberUtil.isDouble(valueStr)) {
            throw new UDISTaskExecutorException(TaskExecuteErrorCode.DATA_CONVERT_ERROR.toString());
        }
        return Convert.toLong(valueStr);
    }

    /**
     * value格式为 hh:mm:ss
     *
     * @param value
     * @return
     */
    private GXTime getGxTime(String value, boolean isHundth) {
        int hundth = 0;
        if (isHundth) {
            String[] values = value.split("\\s+");
            value = values[0];
            String hundthValue = values[1];
            hundth = NumberUtils.isDigits(hundthValue) ? Integer.parseInt(hundthValue, 10) : Integer.parseInt(hundthValue, 16);
        }
        String[] datas = value.split(":");
        int hour = NumberUtils.isDigits(datas[0]) ? Integer.parseInt(datas[0], 10) : Integer.parseInt(datas[0], 16);
        int min = NumberUtils.isDigits(datas[1]) ? Integer.parseInt(datas[1], 10) : Integer.parseInt(datas[1], 16);
        int sec = NumberUtils.isDigits(datas[2]) ? Integer.parseInt(datas[2], 10) : Integer.parseInt(datas[2], 16);

        return new GXTime(hour, min, sec, hundth);
    }


    /**
     * value格式为 YYYY-MM-DD
     *带百分秒格式为 hh:mm:ss 00
     *
     * @param value
     * @return
     */
    private GXDate getGxDate(String value, boolean isContainWeek) {
        int week = -1;
        if (isContainWeek) {
            String[] values = value.split("\\s+");
            value = values[0];
            String weekValue = values[1];
            week = NumberUtils.isDigits(weekValue) ? Integer.parseInt(weekValue, 10) : Integer.parseInt(weekValue, 16);
        }
        String[] datas = value.split("-");
        int year = NumberUtils.isDigits(datas[0]) ? Integer.parseInt(datas[0], 10) : Integer.parseInt(datas[0], 16);
        int month = NumberUtils.isDigits(datas[1]) ? Integer.parseInt(datas[1], 10) : Integer.parseInt(datas[1], 16);
        int day = NumberUtils.isDigits(datas[2]) ? Integer.parseInt(datas[2], 10) : Integer.parseInt(datas[2], 16);
        GXDate gxDate = new GXDate(year, month, day);
        if (week != -1) {
            gxDate.setDayOfWeek(week);
        }

        return gxDate;
    }

        /**
         * 处理Vending Token webservice 接口
         *
         * @param task
         * @param atomicTask
         * @param failedMessage
         */
    private void handleSetParameterResult(Task task, AtomicTask atomicTask, String failedMessage) {
        // 失败的话删除后面的任务
        String errorMessage = "";
        if (!isSubTaskGroupLastAtomicTask(task, atomicTask)) {
            removeSetAtomicTaskIfExists(task, atomicTask);
        }
        if (StrUtil.isNotEmpty(failedMessage)) {
            errorMessage = String.format("The item [%s] error: [%s]", getAtomicTaskValue(atomicTask, "refValue"), failedMessage);
        } else {
            errorMessage = String.format("The item [%s] failed", getAtomicTaskValue(atomicTask, "refValue"));
        }
        // send to adapter
        Map<String, Object> taskMap = JSONUtil.toBean(task.getParamJson(), Map.class);
        JSONObject obj = JSONUtil.createObj();
        String tokenXmlStr = (String) taskMap.get("vendingXmlRequest");
        obj.put("VendingType", "setParameter");
        obj.put("vendingXmlRequest", tokenXmlStr);
        obj.put("errorMessage", errorMessage);
        obj.put("replyCode", "0.2");
        kafkaTemplate.send(TaskKafkaTopic.TASK_VENDING_RESULT_TO_ADAPTER, JSONUtil.toJsonStr(obj).getBytes(StandardCharsets.UTF_8));
    }

    private String getAtomicTaskValue(AtomicTask atomicTask, String key) {
        Map<String, Object> map = JSONUtil.toBean(atomicTask.getAtomicTaskParam(), Map.class);
        if (map.containsKey(key) && null != map.get(key)) {
            return (String) map.get(key);
        }
        return "";
    }

    private void removeSetAtomicTaskIfExists(Task task, AtomicTask atomicTask) {
        //失败的话 结束后续所有任务
        AtomicTask atTask = taskDAO.atomicTaskQueuePopReverse(task.getTaskNo());
        String termQueueId = taskDAO.getTerminalTaskListKey(task);
        taskDAO.terminalTaskQueuePop(termQueueId);
        taskDAO.atomicTaskQueueDelete(task.getTaskNo());
        taskDAO.clearTaskProcessingAtomic(task.getTaskNo());
        log.info("remove atomicTask {} ", atTask.getAtomicTaskNo());
    }

    /**
     * 需要特殊处理的结果，返回对应的handler, 否则返回null
     *
     * @param atomicTask
     * @return
     */
    private Class getHandlerClass(AtomicTask atomicTask) throws UDISTaskExecutorException {
        Class cla = null;
        log.debug("OperationGroup={}", OperationGroup.forId(atomicTask.getGroupId().intValue()));
        switch (OperationGroup.forId(atomicTask.getGroupId().intValue())) {
            case StepTariffActiveDateSet:
            case StPaymentControlConfigSet:
            case StFunctionControlConfigSet:
            case StepTariffBackUpRatePriceSet:
            case StepTariffBackUpStepSet:
                cla = SetStepTariffHandler.class;
                break;
            default:
                cla = SetGeneralParamHandler.class;
        }
        return cla;
    }
}
